/* Tests if there is function/variable names that doesn't match their NID and display their name. You need beecrypt to compile this. */

#include <stdio.h>
#include <string.h>
#include <beecrypt/sha1.h>
#include <libxml/parser.h>

#define forEachChild(lastnode, curnode) for(curnode = lastnode->xmlChildrenNode; curnode != NULL; curnode = curnode->next)
#define hasGoodName(node, nodeName) (!xmlStrcmp(node->name, (const xmlChar*)nodeName))

int validSha1(char *nidStr, char *str)
{
    char nid_le[9], nid[9];
    char buf[3];
    char sha1[41];
    char digest[20];
    sha1Param sp;
    int i;

    sscanf(nidStr, "0x%8s", nid);

    nid_le[0] = nid[6];
    nid_le[1] = nid[7];
    nid_le[2] = nid[4];
    nid_le[3] = nid[5];
    nid_le[4] = nid[2];
    nid_le[5] = nid[3];
    nid_le[6] = nid[0];
    nid_le[7] = nid[1];
    nid_le[8] = '\0';

    sha1Reset(&sp);

    sha1Update(&sp, str, strlen(str));
    sha1Digest(&sp, digest);

    sha1[0] = 0;
    for (i = 0; i < 20; i++) {
        sprintf(buf, "%02X", (unsigned char)digest[i]);
        strcat(sha1, buf);
    }

    if (strncmp(sha1, nid_le, 8) != 0)
        return 0;
    return 1;
}

int main(int argc, char *argv[])
{
    xmlDocPtr doc;
    xmlNodePtr cur, prxContent, lib, libContent, var, varContent, func, funcContent;

    if (argc < 2)
        exit(1);

    doc = xmlParseFile(argv[1]);

    cur = xmlDocGetRootElement(doc);
    if (cur == NULL || xmlStrcmp(cur->name, (const xmlChar*)"PSPLIBDOC"))
    {   
        printf("File is not a valid libdoc! It doesn't have the 'PSPLIBDOC' category!\n");
        xmlFreeDoc(doc);
        return 1;
    }

    for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next)
        if (!xmlStrcmp(cur->name, (const xmlChar*)"PRXFILES"))
            break;

    if (cur == NULL)
    {   
        printf("File is not a valid libdoc! It doesn't have the 'PRXFILES' category (%p, %s, %d)!\n", cur, cur->name, (cur->type == XML_ELEMENT_NODE));
        xmlFreeDoc(doc);
        return 1;
    }

    forEachChild(cur, cur)
    {
        if (hasGoodName(cur, "PRXFILE"))
        {
            forEachChild(cur, prxContent)
            {
                if (hasGoodName(prxContent, "LIBRARIES"))
                {
                    forEachChild(prxContent, lib)
                    {
                        if (hasGoodName(lib, "LIBRARY"))
                        {
                            forEachChild(lib, libContent)
                            {
                                if (hasGoodName(libContent, "VARIABLES"))
                                {
                                    forEachChild(libContent, var)
                                    {
                                        if (hasGoodName(var, "VARIABLE"))
                                        {
                                            xmlChar *name, *nid;
                                            name = nid = NULL;
                                            forEachChild(var, varContent)
                                            {
                                                if (hasGoodName(varContent, "NAME"))
                                                    name = xmlNodeGetContent(varContent);
                                                else if (hasGoodName(varContent, "NID"))
                                                    nid = xmlNodeGetContent(varContent);
                                                if (name && nid)
                                                {
                                                    if (!validSha1(nid, name))
                                                        printf("Var : invalid NID: current %s, name %s\n", nid, name);
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                                else if (hasGoodName(libContent, "FUNCTIONS"))
                                {
                                    forEachChild(libContent, func)
                                    {
                                        if (hasGoodName(func, "FUNCTION"))
                                        {
                                            xmlChar *name, *nid;
                                            name = nid = NULL;
                                            forEachChild(func, funcContent)
                                            {
                                                if (hasGoodName(funcContent, "NAME"))
                                                    name = xmlNodeGetContent(funcContent);
                                                else if (hasGoodName(funcContent, "NID"))
                                                    nid  = xmlNodeGetContent(funcContent);
                                                if (name && nid)
                                                {
                                                    if (!validSha1(nid, name))
                                                        printf("Func: invalid NID: current %s, name %s\n", nid, name);
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    xmlFreeDoc(doc);

    return 0;
}

